<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>渲染函数 | Vue.js</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link href="https://fonts.googleapis.com/css?family=Inter:300,400,500,600|Open+Sans:400,600;display=swap" rel="stylesheet">
    <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <link rel="icon" href="/vue3/logo.png">
    <link rel="manifest" href="/vue3/manifest.json">
    <link rel="apple-touch-icon" href="/vue3/images/icons/apple-icon-152x152.png">
    <script src="https://player.youku.com/iframeapi"></script>
    <meta name="description" content="Vue.js - The 渐进式 JavaScript 框架">
    <meta name="theme-color" content="#3eaf7c">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="msapplication-TileImage" content="/images/icons/ms-icon-144x144.png">
    <meta name="msapplication-TileColor" content="#000000">
    
    <link rel="preload" href="/vue3/assets/css/0.styles.9bf58a16.css" as="style"><link rel="preload" href="/vue3/assets/js/app.9f011487.js" as="script"><link rel="preload" href="/vue3/assets/js/11.bea13863.js" as="script"><link rel="preload" href="/vue3/assets/js/163.c2f8c96a.js" as="script"><link rel="preload" href="/vue3/assets/js/23.f23a1976.js" as="script"><link rel="prefetch" href="/vue3/assets/js/1.98516ad1.js"><link rel="prefetch" href="/vue3/assets/js/100.94330a5d.js"><link rel="prefetch" href="/vue3/assets/js/101.560a6b49.js"><link rel="prefetch" href="/vue3/assets/js/102.f12c4d91.js"><link rel="prefetch" href="/vue3/assets/js/103.be709996.js"><link rel="prefetch" href="/vue3/assets/js/104.49fdebb1.js"><link rel="prefetch" href="/vue3/assets/js/105.df17d42d.js"><link rel="prefetch" href="/vue3/assets/js/106.fa0a51b7.js"><link rel="prefetch" href="/vue3/assets/js/107.392361bf.js"><link rel="prefetch" href="/vue3/assets/js/108.af6fc4d6.js"><link rel="prefetch" href="/vue3/assets/js/109.18bcf602.js"><link rel="prefetch" href="/vue3/assets/js/110.052b8c4c.js"><link rel="prefetch" href="/vue3/assets/js/111.528533a3.js"><link rel="prefetch" href="/vue3/assets/js/112.28359168.js"><link rel="prefetch" href="/vue3/assets/js/113.190e7aff.js"><link rel="prefetch" href="/vue3/assets/js/114.dddc32bb.js"><link rel="prefetch" href="/vue3/assets/js/115.7924a11d.js"><link rel="prefetch" href="/vue3/assets/js/116.5836841c.js"><link rel="prefetch" href="/vue3/assets/js/117.1e3523ad.js"><link rel="prefetch" href="/vue3/assets/js/118.fda02ea3.js"><link rel="prefetch" href="/vue3/assets/js/119.c56ed999.js"><link rel="prefetch" href="/vue3/assets/js/12.11fdef37.js"><link rel="prefetch" href="/vue3/assets/js/120.14653326.js"><link rel="prefetch" href="/vue3/assets/js/121.5bdc69d1.js"><link rel="prefetch" href="/vue3/assets/js/122.ea246bef.js"><link rel="prefetch" href="/vue3/assets/js/123.1a041b0d.js"><link rel="prefetch" href="/vue3/assets/js/124.4849397b.js"><link rel="prefetch" href="/vue3/assets/js/125.f8a4d9a1.js"><link rel="prefetch" href="/vue3/assets/js/126.e6f8c88f.js"><link rel="prefetch" href="/vue3/assets/js/127.bb0d0c14.js"><link rel="prefetch" href="/vue3/assets/js/128.6fcdf065.js"><link rel="prefetch" href="/vue3/assets/js/129.d37419cf.js"><link rel="prefetch" href="/vue3/assets/js/13.84b5a427.js"><link rel="prefetch" href="/vue3/assets/js/130.2ff76428.js"><link rel="prefetch" href="/vue3/assets/js/131.dbd74031.js"><link rel="prefetch" href="/vue3/assets/js/132.b4ca1a54.js"><link rel="prefetch" href="/vue3/assets/js/133.95a81c57.js"><link rel="prefetch" href="/vue3/assets/js/134.da6a25f1.js"><link rel="prefetch" href="/vue3/assets/js/135.46cd4ce4.js"><link rel="prefetch" href="/vue3/assets/js/136.c908c444.js"><link rel="prefetch" href="/vue3/assets/js/137.838c736d.js"><link rel="prefetch" href="/vue3/assets/js/138.5f56ac41.js"><link rel="prefetch" href="/vue3/assets/js/139.2d3218e7.js"><link rel="prefetch" href="/vue3/assets/js/14.ccde2ff7.js"><link rel="prefetch" href="/vue3/assets/js/140.73a6c08b.js"><link rel="prefetch" href="/vue3/assets/js/141.e6e97fa2.js"><link rel="prefetch" href="/vue3/assets/js/142.78b66660.js"><link rel="prefetch" href="/vue3/assets/js/143.18a5f522.js"><link rel="prefetch" href="/vue3/assets/js/144.007967ab.js"><link rel="prefetch" href="/vue3/assets/js/145.69c6c622.js"><link rel="prefetch" href="/vue3/assets/js/146.5eb14458.js"><link rel="prefetch" href="/vue3/assets/js/147.01b7b88c.js"><link rel="prefetch" href="/vue3/assets/js/148.c4464ffa.js"><link rel="prefetch" href="/vue3/assets/js/149.66883751.js"><link rel="prefetch" href="/vue3/assets/js/15.6957b547.js"><link rel="prefetch" href="/vue3/assets/js/150.03ccd0c3.js"><link rel="prefetch" href="/vue3/assets/js/151.5cb25376.js"><link rel="prefetch" href="/vue3/assets/js/152.51fa843b.js"><link rel="prefetch" href="/vue3/assets/js/153.c280bbfc.js"><link rel="prefetch" href="/vue3/assets/js/154.3c1208bb.js"><link rel="prefetch" href="/vue3/assets/js/155.f2bec114.js"><link rel="prefetch" href="/vue3/assets/js/156.9d563e5f.js"><link rel="prefetch" href="/vue3/assets/js/157.09a62483.js"><link rel="prefetch" href="/vue3/assets/js/158.e8ee954d.js"><link rel="prefetch" href="/vue3/assets/js/159.806c0da5.js"><link rel="prefetch" href="/vue3/assets/js/16.1c3a9fe2.js"><link rel="prefetch" href="/vue3/assets/js/160.70fe7ee3.js"><link rel="prefetch" href="/vue3/assets/js/161.7b67e86f.js"><link rel="prefetch" href="/vue3/assets/js/162.d2cb71f8.js"><link rel="prefetch" href="/vue3/assets/js/164.c0ce5d22.js"><link rel="prefetch" href="/vue3/assets/js/165.dd31fc10.js"><link rel="prefetch" href="/vue3/assets/js/166.861df1bd.js"><link rel="prefetch" href="/vue3/assets/js/167.8cade3be.js"><link rel="prefetch" href="/vue3/assets/js/168.d384c54a.js"><link rel="prefetch" href="/vue3/assets/js/169.266b17c8.js"><link rel="prefetch" href="/vue3/assets/js/17.13ae2912.js"><link rel="prefetch" href="/vue3/assets/js/170.8da5cca1.js"><link rel="prefetch" href="/vue3/assets/js/171.59233d62.js"><link rel="prefetch" href="/vue3/assets/js/172.e2ff7db9.js"><link rel="prefetch" href="/vue3/assets/js/173.4fae5fdf.js"><link rel="prefetch" href="/vue3/assets/js/174.25d65654.js"><link rel="prefetch" href="/vue3/assets/js/175.0fd8e932.js"><link rel="prefetch" href="/vue3/assets/js/176.afbb20d7.js"><link rel="prefetch" href="/vue3/assets/js/177.3fce4ef4.js"><link rel="prefetch" href="/vue3/assets/js/178.a69eab8f.js"><link rel="prefetch" href="/vue3/assets/js/179.b9c69246.js"><link rel="prefetch" href="/vue3/assets/js/18.2176f64f.js"><link rel="prefetch" href="/vue3/assets/js/180.80eaf61f.js"><link rel="prefetch" href="/vue3/assets/js/181.8c9ea68f.js"><link rel="prefetch" href="/vue3/assets/js/182.363237b2.js"><link rel="prefetch" href="/vue3/assets/js/183.1bcce34d.js"><link rel="prefetch" href="/vue3/assets/js/184.63965c38.js"><link rel="prefetch" href="/vue3/assets/js/185.145d17f7.js"><link rel="prefetch" href="/vue3/assets/js/186.01c28041.js"><link rel="prefetch" href="/vue3/assets/js/187.651fc5e1.js"><link rel="prefetch" href="/vue3/assets/js/188.371a53d8.js"><link rel="prefetch" href="/vue3/assets/js/189.21a8c4f3.js"><link rel="prefetch" href="/vue3/assets/js/19.f35e6099.js"><link rel="prefetch" href="/vue3/assets/js/2.655ed906.js"><link rel="prefetch" href="/vue3/assets/js/20.6a9108db.js"><link rel="prefetch" href="/vue3/assets/js/21.b90deaac.js"><link rel="prefetch" href="/vue3/assets/js/22.2da4161c.js"><link rel="prefetch" href="/vue3/assets/js/24.0f4c4cde.js"><link rel="prefetch" href="/vue3/assets/js/25.3a155505.js"><link rel="prefetch" href="/vue3/assets/js/26.d7a45b3e.js"><link rel="prefetch" href="/vue3/assets/js/27.3c237b85.js"><link rel="prefetch" href="/vue3/assets/js/28.1722182e.js"><link rel="prefetch" href="/vue3/assets/js/29.158159ee.js"><link rel="prefetch" href="/vue3/assets/js/3.9e67029d.js"><link rel="prefetch" href="/vue3/assets/js/30.085c3faf.js"><link rel="prefetch" href="/vue3/assets/js/31.d95eaf7d.js"><link rel="prefetch" href="/vue3/assets/js/32.75be14cd.js"><link rel="prefetch" href="/vue3/assets/js/33.b9adbce6.js"><link rel="prefetch" href="/vue3/assets/js/34.ef96058c.js"><link rel="prefetch" href="/vue3/assets/js/35.f2d110b9.js"><link rel="prefetch" href="/vue3/assets/js/36.11e69166.js"><link rel="prefetch" href="/vue3/assets/js/37.d51d98ce.js"><link rel="prefetch" href="/vue3/assets/js/38.ba303c3e.js"><link rel="prefetch" href="/vue3/assets/js/39.7af701c4.js"><link rel="prefetch" href="/vue3/assets/js/4.2768033f.js"><link rel="prefetch" href="/vue3/assets/js/40.50b39df3.js"><link rel="prefetch" href="/vue3/assets/js/41.377521c6.js"><link rel="prefetch" href="/vue3/assets/js/42.3b63f9c9.js"><link rel="prefetch" href="/vue3/assets/js/43.98898a3b.js"><link rel="prefetch" href="/vue3/assets/js/44.29a6e6a2.js"><link rel="prefetch" href="/vue3/assets/js/45.7d0883fe.js"><link rel="prefetch" href="/vue3/assets/js/46.4e93f7dd.js"><link rel="prefetch" href="/vue3/assets/js/47.4c629b92.js"><link rel="prefetch" href="/vue3/assets/js/48.f1bf29a9.js"><link rel="prefetch" href="/vue3/assets/js/49.a49482a4.js"><link rel="prefetch" href="/vue3/assets/js/5.175dbe8f.js"><link rel="prefetch" href="/vue3/assets/js/50.dbad5716.js"><link rel="prefetch" href="/vue3/assets/js/51.76b7354d.js"><link rel="prefetch" href="/vue3/assets/js/52.3a1a9a63.js"><link rel="prefetch" href="/vue3/assets/js/53.be592e24.js"><link rel="prefetch" href="/vue3/assets/js/54.d97c6e79.js"><link rel="prefetch" href="/vue3/assets/js/55.eff64da2.js"><link rel="prefetch" href="/vue3/assets/js/56.e3dc0e44.js"><link rel="prefetch" href="/vue3/assets/js/57.d7b38bdd.js"><link rel="prefetch" href="/vue3/assets/js/58.fdc076c9.js"><link rel="prefetch" href="/vue3/assets/js/59.9f11e0ea.js"><link rel="prefetch" href="/vue3/assets/js/6.c6369861.js"><link rel="prefetch" href="/vue3/assets/js/60.a818862d.js"><link rel="prefetch" href="/vue3/assets/js/61.bb9ab96c.js"><link rel="prefetch" href="/vue3/assets/js/62.116aefff.js"><link rel="prefetch" href="/vue3/assets/js/63.be6c07d0.js"><link rel="prefetch" href="/vue3/assets/js/64.0ad95216.js"><link rel="prefetch" href="/vue3/assets/js/65.f8749c54.js"><link rel="prefetch" href="/vue3/assets/js/66.7680f482.js"><link rel="prefetch" href="/vue3/assets/js/67.6fba4d5a.js"><link rel="prefetch" href="/vue3/assets/js/68.ed63b04b.js"><link rel="prefetch" href="/vue3/assets/js/69.73b3bf13.js"><link rel="prefetch" href="/vue3/assets/js/7.cd1985fe.js"><link rel="prefetch" href="/vue3/assets/js/70.6e7dc295.js"><link rel="prefetch" href="/vue3/assets/js/71.32c17a2a.js"><link rel="prefetch" href="/vue3/assets/js/72.ab8b426d.js"><link rel="prefetch" href="/vue3/assets/js/73.73838f6c.js"><link rel="prefetch" href="/vue3/assets/js/74.c3c5f3e6.js"><link rel="prefetch" href="/vue3/assets/js/75.5f63164c.js"><link rel="prefetch" href="/vue3/assets/js/76.6071fb5c.js"><link rel="prefetch" href="/vue3/assets/js/77.1f274f68.js"><link rel="prefetch" href="/vue3/assets/js/78.16d4c50b.js"><link rel="prefetch" href="/vue3/assets/js/79.fc2b2e03.js"><link rel="prefetch" href="/vue3/assets/js/80.42173ce4.js"><link rel="prefetch" href="/vue3/assets/js/81.51405a99.js"><link rel="prefetch" href="/vue3/assets/js/82.be2d0e4f.js"><link rel="prefetch" href="/vue3/assets/js/83.75b4d2af.js"><link rel="prefetch" href="/vue3/assets/js/84.fbaa5717.js"><link rel="prefetch" href="/vue3/assets/js/85.60063971.js"><link rel="prefetch" href="/vue3/assets/js/86.cf80c75d.js"><link rel="prefetch" href="/vue3/assets/js/87.eca6cea7.js"><link rel="prefetch" href="/vue3/assets/js/88.3967efe4.js"><link rel="prefetch" href="/vue3/assets/js/89.bf83cb8c.js"><link rel="prefetch" href="/vue3/assets/js/90.96996b25.js"><link rel="prefetch" href="/vue3/assets/js/91.31b5ee41.js"><link rel="prefetch" href="/vue3/assets/js/92.d197feb2.js"><link rel="prefetch" href="/vue3/assets/js/93.b471c7fe.js"><link rel="prefetch" href="/vue3/assets/js/94.b4298707.js"><link rel="prefetch" href="/vue3/assets/js/95.2f91d14f.js"><link rel="prefetch" href="/vue3/assets/js/96.18b64251.js"><link rel="prefetch" href="/vue3/assets/js/97.363729fa.js"><link rel="prefetch" href="/vue3/assets/js/98.cb8f0be4.js"><link rel="prefetch" href="/vue3/assets/js/99.f62cf45d.js"><link rel="prefetch" href="/vue3/assets/js/vendors~docsearch.5cf23a03.js"><link rel="prefetch" href="/vue3/assets/js/vendors~search-page.d14326ff.js">
    <link rel="stylesheet" href="/vue3/assets/css/0.styles.9bf58a16.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><!----> <header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/vue3/" class="home-link router-link-active"><img src="/vue3/logo.png" alt="Vue.js" class="logo"> <span class="site-name can-hide">Vue.js</span></a> <span style="font-size:.9rem;color:#2c3e50;margin-left:20px;">非官方文档，查看官方文档请移步<a href="https://v3.cn.vuejs.org/" target="_blank">这里</a></span> <div class="links"><!----> <nav class="nav-links can-hide"><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="文档菜单" class="dropdown-title"><span class="title">文档</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/vue3/guide/introduction.html" class="nav-link">
  教程
</a></li><li class="dropdown-item"><!----> <a href="/vue3/style-guide/" class="nav-link">
  风格指南
</a></li><li class="dropdown-item"><!----> <a href="/vue3/cookbook/" class="nav-link">
  Cookbook
</a></li><li class="dropdown-item"><!----> <a href="/vue3/examples/markdown.html" class="nav-link">
  示例
</a></li><li class="dropdown-item"><!----> <a href="/vue3/guide/contributing/writing-guide.html" class="nav-link">
  贡献文档
</a></li><li class="dropdown-item"><!----> <a href="/vue3/guide/migration/introduction.html" class="nav-link">
  从 Vue 2 迁移
</a></li></ul></div></div><div class="nav-item"><a href="/vue3/api/" class="nav-link">
  API 参考
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="生态系统" class="dropdown-title"><span class="title">生态系统</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          社区
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/vue3/community/team/" class="nav-link">
  团队
</a></li><li class="dropdown-subitem"><a href="/vue3/community/partners.html" class="nav-link">
  合作伙伴
</a></li><li class="dropdown-subitem"><a href="/vue3/community/join/" class="nav-link">
  加入
</a></li><li class="dropdown-subitem"><a href="/vue3/community/themes/" class="nav-link">
  主题
</a></li></ul></li><li class="dropdown-item"><h4>
          官方项目
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://next.router.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vue Router
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://next.vuex.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vuex
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://cli.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vue CLI
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://next.vue-test-utils.vuejs.org/guide/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vue Test Utils
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://devtools.vuejs.org" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Devtools
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://news.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Weekly news
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://blog.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Blog
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="支持 Vue" class="dropdown-title"><span class="title">支持 Vue</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/vue3/support-vuejs/#一次性捐款" class="nav-link">
  一次性捐款
</a></li><li class="dropdown-item"><!----> <a href="/vue3/support-vuejs/#周期性赞助" class="nav-link">
  周期性捐款
</a></li><li class="dropdown-item"><!----> <a href="https://www.smallsticker.com/%E8%B4%B4%E7%BA%B8/vue.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
  贴纸
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://osholic.com/?utm_source=vue&amp;utm_medium=dropdown" target="_blank" rel="noopener noreferrer" class="nav-link external">
  周边
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://vue.threadless.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  T-Shirt 商店
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="多语言" class="dropdown-title"><span class="title">多语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://v3.vuejs.org/" target="_blank" class="nav-link external">
  English
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://v3.ko.vuejs.org/" target="_blank" class="nav-link external">
  한국어
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://v3.ja.vuejs.org/" target="_blank" class="nav-link external">
  日本語
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://v3.ru.vuejs.org/ru/" target="_blank" class="nav-link external">
  Русский
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="/vue3/guide/contributing/translations.html#community-translations" class="nav-link">
  更多翻译
</a></li></ul></div></div> <a href="https://github.com/vuejs/docs-next-zh-cn" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav> <div id="docsearch"></div></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="文档菜单" class="dropdown-title"><span class="title">文档</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/vue3/guide/introduction.html" class="nav-link">
  教程
</a></li><li class="dropdown-item"><!----> <a href="/vue3/style-guide/" class="nav-link">
  风格指南
</a></li><li class="dropdown-item"><!----> <a href="/vue3/cookbook/" class="nav-link">
  Cookbook
</a></li><li class="dropdown-item"><!----> <a href="/vue3/examples/markdown.html" class="nav-link">
  示例
</a></li><li class="dropdown-item"><!----> <a href="/vue3/guide/contributing/writing-guide.html" class="nav-link">
  贡献文档
</a></li><li class="dropdown-item"><!----> <a href="/vue3/guide/migration/introduction.html" class="nav-link">
  从 Vue 2 迁移
</a></li></ul></div></div><div class="nav-item"><a href="/vue3/api/" class="nav-link">
  API 参考
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="生态系统" class="dropdown-title"><span class="title">生态系统</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          社区
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/vue3/community/team/" class="nav-link">
  团队
</a></li><li class="dropdown-subitem"><a href="/vue3/community/partners.html" class="nav-link">
  合作伙伴
</a></li><li class="dropdown-subitem"><a href="/vue3/community/join/" class="nav-link">
  加入
</a></li><li class="dropdown-subitem"><a href="/vue3/community/themes/" class="nav-link">
  主题
</a></li></ul></li><li class="dropdown-item"><h4>
          官方项目
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://next.router.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vue Router
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://next.vuex.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vuex
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://cli.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vue CLI
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://next.vue-test-utils.vuejs.org/guide/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Vue Test Utils
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://devtools.vuejs.org" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Devtools
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://news.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Weekly news
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="https://blog.vuejs.org/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Blog
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="支持 Vue" class="dropdown-title"><span class="title">支持 Vue</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/vue3/support-vuejs/#一次性捐款" class="nav-link">
  一次性捐款
</a></li><li class="dropdown-item"><!----> <a href="/vue3/support-vuejs/#周期性赞助" class="nav-link">
  周期性捐款
</a></li><li class="dropdown-item"><!----> <a href="https://www.smallsticker.com/%E8%B4%B4%E7%BA%B8/vue.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
  贴纸
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://osholic.com/?utm_source=vue&amp;utm_medium=dropdown" target="_blank" rel="noopener noreferrer" class="nav-link external">
  周边
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://vue.threadless.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  T-Shirt 商店
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="多语言" class="dropdown-title"><span class="title">多语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://v3.vuejs.org/" target="_blank" class="nav-link external">
  English
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://v3.ko.vuejs.org/" target="_blank" class="nav-link external">
  한국어
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://v3.ja.vuejs.org/" target="_blank" class="nav-link external">
  日本語
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://v3.ru.vuejs.org/ru/" target="_blank" class="nav-link external">
  Русский
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="/vue3/guide/contributing/translations.html#community-translations" class="nav-link">
  更多翻译
</a></li></ul></div></div> <a href="https://github.com/vuejs/docs-next-zh-cn" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>基础</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/installation.html" class="sidebar-link">安装</a></li><li><a href="/vue3/guide/introduction.html" class="sidebar-link">介绍</a></li><li><a href="/vue3/guide/instance.html" class="sidebar-link">应用 &amp; 组件实例</a></li><li><a href="/vue3/guide/template-syntax.html" class="sidebar-link">模板语法</a></li><li><a href="/vue3/guide/data-methods.html" class="sidebar-link">Data Property 和方法</a></li><li><a href="/vue3/guide/computed.html" class="sidebar-link">计算属性和侦听器</a></li><li><a href="/vue3/guide/class-and-style.html" class="sidebar-link">Class 与 Style 绑定</a></li><li><a href="/vue3/guide/conditional.html" class="sidebar-link">条件渲染</a></li><li><a href="/vue3/guide/list.html" class="sidebar-link">列表渲染</a></li><li><a href="/vue3/guide/events.html" class="sidebar-link">事件处理</a></li><li><a href="/vue3/guide/forms.html" class="sidebar-link">表单输入绑定</a></li><li><a href="/vue3/guide/component-basics.html" class="sidebar-link">组件基础</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>深入组件</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/component-registration.html" class="sidebar-link">组件注册</a></li><li><a href="/vue3/guide/component-props.html" class="sidebar-link">Props</a></li><li><a href="/vue3/guide/component-attrs.html" class="sidebar-link">非 Prop 的 Attribute</a></li><li><a href="/vue3/guide/component-custom-events.html" class="sidebar-link">自定义事件</a></li><li><a href="/vue3/guide/component-slots.html" class="sidebar-link">插槽</a></li><li><a href="/vue3/guide/component-provide-inject.html" class="sidebar-link">Provide / Inject</a></li><li><a href="/vue3/guide/component-dynamic-async.html" class="sidebar-link">动态组件 &amp; 异步组件</a></li><li><a href="/vue3/guide/component-template-refs.html" class="sidebar-link">模板引用</a></li><li><a href="/vue3/guide/component-edge-cases.html" class="sidebar-link">处理边界情况</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>过渡 &amp; 动画</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/transitions-overview.html" class="sidebar-link">过渡 &amp; 动画概述</a></li><li><a href="/vue3/guide/transitions-enterleave.html" class="sidebar-link">进入过渡 &amp; 离开过渡</a></li><li><a href="/vue3/guide/transitions-list.html" class="sidebar-link">列表过渡</a></li><li><a href="/vue3/guide/transitions-state.html" class="sidebar-link">状态过渡</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>可复用 &amp; 组合</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><section class="sidebar-group collapsable is-sub-group depth-1"><p class="sidebar-heading open"><span>组合式 API</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/composition-api-introduction.html" class="sidebar-link">介绍</a></li><li><a href="/vue3/guide/composition-api-setup.html" class="sidebar-link">Setup</a></li><li><a href="/vue3/guide/composition-api-lifecycle-hooks.html" class="sidebar-link">生命周期钩子</a></li><li><a href="/vue3/guide/composition-api-provide-inject.html" class="sidebar-link">Provide / Inject</a></li><li><a href="/vue3/guide/composition-api-template-refs.html" class="sidebar-link">模板引用</a></li></ul></section></li><li><a href="/vue3/guide/mixins.html" class="sidebar-link">Mixin</a></li><li><a href="/vue3/guide/custom-directive.html" class="sidebar-link">自定义指令</a></li><li><a href="/vue3/guide/teleport.html" class="sidebar-link">Teleport</a></li><li><a href="/vue3/guide/render-function.html" aria-current="page" class="active sidebar-link">渲染函数</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#dom-树" class="sidebar-link">DOM 树</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#虚拟-dom-树" class="sidebar-link">虚拟 DOM 树</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#h-参数" class="sidebar-link">h() 参数</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#完整实例" class="sidebar-link">完整实例</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#约束" class="sidebar-link">约束</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#vnodes-必须唯一" class="sidebar-link">VNodes 必须唯一</a></li></ul></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#创建组件-vnode" class="sidebar-link">创建组件 VNode</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#使用-javascript-代替模板功能" class="sidebar-link">使用 JavaScript 代替模板功能</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#v-if-和-v-for" class="sidebar-link">v-if 和 v-for</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#v-model" class="sidebar-link">v-model</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#v-on" class="sidebar-link">v-on</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#插槽" class="sidebar-link">插槽</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#component-和-is" class="sidebar-link">&lt;component&gt; 和 is</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#自定义指令" class="sidebar-link">自定义指令</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#内置组件" class="sidebar-link">内置组件</a></li></ul></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#渲染函数的返回值" class="sidebar-link">渲染函数的返回值</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#jsx" class="sidebar-link">JSX</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#函数式组件" class="sidebar-link">函数式组件</a></li><li class="sidebar-sub-header"><a href="/vue3/guide/render-function.html#模板编译" class="sidebar-link">模板编译</a></li></ul></li><li><a href="/vue3/guide/plugins.html" class="sidebar-link">插件</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>高阶指南</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/web-components.html" class="sidebar-link">Vue 与 Web Components</a></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><p class="sidebar-heading"><span>响应性</span> <span class="arrow right"></span></p> <!----></section></li><li><a href="/vue3/guide/optimizations.html" class="sidebar-link">渲染机制和优化</a></li><li><a href="/vue3/guide/change-detection.html" class="sidebar-link">Vue 2 中更改检测的注意事项</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>工具</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/single-file-component.html" class="sidebar-link">单文件组件</a></li><li><a href="/vue3/guide/testing.html" class="sidebar-link">测试</a></li><li><a href="/vue3/guide/typescript-support.html" class="sidebar-link">TypeScript 支持</a></li><li><a href="/vue3/guide/mobile.html" class="sidebar-link">移动端</a></li><li><a href="/vue3/guide/tooling/deployment.html" class="sidebar-link">生产环境部署</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>规模化</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/routing.html" class="sidebar-link">路由</a></li><li><a href="/vue3/guide/state-management.html" class="sidebar-link">状态管理</a></li><li><a href="/vue3/guide/ssr.html" class="sidebar-link">服务端渲染</a></li><li><a href="/vue3/guide/security.html" class="sidebar-link">安全</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>无障碍</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue3/guide/a11y-basics.html" class="sidebar-link">基础</a></li><li><a href="/vue3/guide/a11y-semantics.html" class="sidebar-link">语义</a></li><li><a href="/vue3/guide/a11y-standards.html" class="sidebar-link">标准</a></li><li><a href="/vue3/guide/a11y-resources.html" class="sidebar-link">资源</a></li></ul></section></li></ul> </aside> <main class="page"><div class="carbon-ads"></div>  <div class="theme-default-content content__default"><h1 id="渲染函数"><a href="#渲染函数" class="header-anchor">#</a> 渲染函数</h1> <p>Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中，你真的需要 JavaScript 的完全编程的能力。这时你可以用<strong>渲染函数</strong>，它比模板更接近编译器。</p> <p>让我们深入一个简单的例子，这个例子里 <code>render</code> 函数很实用。假设我们要生成一些带锚点的标题：</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>hello-world<span class="token punctuation">&quot;</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>#hello-world<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    Hello world!
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>锚点标题的使用非常频繁，我们应该创建一个组件：</p> <div class="language-vue-html line-numbers-mode"><pre class="language-vue-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>anchored-heading</span> <span class="token directive"><span class="token punctuation directive-shorthand">:</span><span class="token directive-modifier"><span class="token punctuation">l</span><span class="token punctuation">e</span><span class="token punctuation">v</span><span class="token punctuation">e</span><span class="token punctuation">l</span></span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js"><span class="token number">1</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>Hello world!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>anchored-heading</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>当开始写一个只能通过 <code>level</code> prop 动态生成标题 (heading) 的组件时，我们很快就可以得出这样的结论：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> createApp <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">createApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>

app<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">'anchored-heading'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  template<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><span class="language-html">
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token directive"><span class="token identifier directive-name">v-if</span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js">level <span class="token operator">===</span> <span class="token number">1</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>slot</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token directive"><span class="token identifier directive-name">v-else-if</span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js">level <span class="token operator">===</span> <span class="token number">2</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>slot</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span> <span class="token directive"><span class="token identifier directive-name">v-else-if</span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js">level <span class="token operator">===</span> <span class="token number">3</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>slot</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h4</span> <span class="token directive"><span class="token identifier directive-name">v-else-if</span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js">level <span class="token operator">===</span> <span class="token number">4</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>slot</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h4</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token directive"><span class="token identifier directive-name">v-else-if</span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js">level <span class="token operator">===</span> <span class="token number">5</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>slot</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h6</span> <span class="token directive"><span class="token identifier directive-name">v-else-if</span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js">level <span class="token operator">===</span> <span class="token number">6</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>slot</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>slot</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h6</span><span class="token punctuation">&gt;</span></span>
  </span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
  props<span class="token operator">:</span> <span class="token punctuation">{</span>
    level<span class="token operator">:</span> <span class="token punctuation">{</span>
      type<span class="token operator">:</span> Number<span class="token punctuation">,</span>
      required<span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br></div></div><p>这个模板感觉不太好。它不仅冗长，而且我们为每个级别标题重复书写了 <code>&lt;slot&gt;&lt;/slot&gt;</code>。当我们添加锚元素时，我们必须在每个 <code>v-if/v-else-if</code> 分支中再次重复它。</p> <p>虽然模板在大多数组件中都非常好用，但是显然在这里它就不合适了。那么，我们来尝试使用 <code>render</code> 函数重写上面的例子：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> createApp<span class="token punctuation">,</span> h <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">createApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>

app<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">'anchored-heading'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>
      <span class="token string">'h'</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>level<span class="token punctuation">,</span> <span class="token comment">// 标签名</span>
      <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// prop 或 attribute</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 包含其子节点的数组</span>
    <span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  props<span class="token operator">:</span> <span class="token punctuation">{</span>
    level<span class="token operator">:</span> <span class="token punctuation">{</span>
      type<span class="token operator">:</span> Number<span class="token punctuation">,</span>
      required<span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p><code>render()</code> 函数的实现要精简得多，但是需要非常熟悉组件的实例 property。在这个例子中，你需要知道，向组件中传递不带 <code>v-slot</code> 指令的子节点时，比如 <code>anchored-heading</code> 中的 <code>Hello world!</code> ，这些子节点被存储在组件实例中的 <code>$slots.default</code> 中。如果你还不了解，<strong>在深入渲染函数之前推荐阅读<a href="/vue3/api/instance-properties.html">实例 property API</a></strong>。</p> <h2 id="dom-树"><a href="#dom-树" class="header-anchor">#</a> DOM 树</h2> <p>在深入渲染函数之前，了解一些浏览器的工作原理是很重要的。以下面这段 HTML 为例：</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>My title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
  Some text content
  <span class="token comment">&lt;!-- TODO: Add tagline --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>当浏览器读到这些代码时，它会建立一个 <a href="https://javascript.info/dom-nodes" target="_blank" rel="noopener noreferrer">”DOM 节点“ 树<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 来保持追踪所有内容，如同你会画一张家谱树来追踪家庭成员的发展一样。</p> <p>上述 HTML 对应的 DOM 节点树如下图所示</p> <p><img src="/vue3/images/dom-tree.png" alt="DOM Tree Visualization"></p> <p>每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样，每个节点都可以有孩子节点 (也就是说每个部分可以包含其它的一些部分)。</p> <p>高效地更新所有这些节点会是比较困难的，不过所幸你不必手动完成这个工作。你只需要告诉 Vue 你希望页面上的 HTML 是什么，这可以是在一个模板里：</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>{{ blogTitle }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>或者一个渲染函数里：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'h1'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>blogTitle<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>在这两种情况下，Vue 都会自动保持页面的更新，即便 <code>blogTitle</code> 发生了改变。</p> <h2 id="虚拟-dom-树"><a href="#虚拟-dom-树" class="header-anchor">#</a> 虚拟 DOM 树</h2> <p>Vue 通过建立一个<strong>虚拟 DOM</strong> 来追踪自己要如何改变真实 DOM。请仔细看这行代码：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'h1'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>blogTitle<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>h()</code> 到底会返回什么呢？其实不是一个<em>实际</em>的 DOM 元素。它更准确的名字可能是 createNodeDescription，因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点，包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”，也常简写它为 <strong>VNode</strong>。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。</p> <h2 id="h-参数"><a href="#h-参数" class="header-anchor">#</a> <code>h()</code> 参数</h2> <p><code>h()</code> 函数是一个用于创建 VNode 的实用程序。也许可以更准确地将其命名为 <code>createVNode()</code>，但由于频繁使用和简洁，它被称为 <code>h()</code> 。它接受三个参数：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// @returns {VNode}</span>
<span class="token function">h</span><span class="token punctuation">(</span>
  <span class="token comment">// {String | Object | Function} tag</span>
  <span class="token comment">// 一个 HTML 标签名、一个组件、一个异步组件、或</span>
  <span class="token comment">// 一个函数式组件。</span>
  <span class="token comment">//</span>
  <span class="token comment">// 必需的。</span>
  <span class="token string">'div'</span><span class="token punctuation">,</span>

  <span class="token comment">// {Object} props</span>
  <span class="token comment">// 与 attribute、prop 和事件相对应的对象。</span>
  <span class="token comment">// 这会在模板中用到。</span>
  <span class="token comment">//</span>
  <span class="token comment">// 可选的。</span>
  <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>

  <span class="token comment">// {String | Array | Object} children</span>
  <span class="token comment">// 子 VNodes, 使用 `h()` 构建,</span>
  <span class="token comment">// 或使用字符串获取 &quot;文本 VNode&quot; 或者</span>
  <span class="token comment">// 有插槽的对象。</span>
  <span class="token comment">//</span>
  <span class="token comment">// 可选的。</span>
  <span class="token punctuation">[</span>
    <span class="token string">'Some text comes first.'</span><span class="token punctuation">,</span>
    <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'h1'</span><span class="token punctuation">,</span> <span class="token string">'A headline'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">h</span><span class="token punctuation">(</span>MyComponent<span class="token punctuation">,</span> <span class="token punctuation">{</span>
      someProp<span class="token operator">:</span> <span class="token string">'foobar'</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><p>如果没有 prop，那么通常可以将 children 作为第二个参数传入。如果会产生歧义，可以将 <code>null</code> 作为第二个参数传入，将 children 作为第三个参数传入。</p> <h2 id="完整实例"><a href="#完整实例" class="header-anchor">#</a> 完整实例</h2> <p>有了这些知识，我们现在可以完成我们最开始想实现的组件：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> createApp<span class="token punctuation">,</span> h <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">createApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">/** 递归地从子节点获取文本 */</span>
<span class="token keyword">function</span> <span class="token function">getChildrenTextContent</span><span class="token punctuation">(</span><span class="token parameter">children</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> children
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">node</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">typeof</span> node<span class="token punctuation">.</span>children <span class="token operator">===</span> <span class="token string">'string'</span>
        <span class="token operator">?</span> node<span class="token punctuation">.</span>children
        <span class="token operator">:</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span>children<span class="token punctuation">)</span>
        <span class="token operator">?</span> <span class="token function">getChildrenTextContent</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span>children<span class="token punctuation">)</span>
        <span class="token operator">:</span> <span class="token string">''</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

app<span class="token punctuation">.</span><span class="token function">component</span><span class="token punctuation">(</span><span class="token string">'anchored-heading'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 从 children 的文本内容中创建短横线分隔 (kebab-case) id。</span>
    <span class="token keyword">const</span> headingId <span class="token operator">=</span> <span class="token function">getChildrenTextContent</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\W+</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span> <span class="token comment">// 用短横线替换非单词字符</span>
      <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(^-|-$)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token comment">// 删除前后短横线</span>

    <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'h'</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>level<span class="token punctuation">,</span> <span class="token punctuation">[</span>
      <span class="token function">h</span><span class="token punctuation">(</span>
        <span class="token string">'a'</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          name<span class="token operator">:</span> headingId<span class="token punctuation">,</span>
          href<span class="token operator">:</span> <span class="token string">'#'</span> <span class="token operator">+</span> headingId
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span>
    <span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  props<span class="token operator">:</span> <span class="token punctuation">{</span>
    level<span class="token operator">:</span> <span class="token punctuation">{</span>
      type<span class="token operator">:</span> Number<span class="token punctuation">,</span>
      required<span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br></div></div><h2 id="约束"><a href="#约束" class="header-anchor">#</a> 约束</h2> <h3 id="vnodes-必须唯一"><a href="#vnodes-必须唯一" class="header-anchor">#</a> VNodes 必须唯一</h3> <p>组件树中的所有 VNode 必须是唯一的。这意味着，下面的渲染函数是不合法的：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> myParagraphVNode <span class="token operator">=</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token string">'hi'</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>
    <span class="token comment">// 错误 - 重复的 Vnode!</span>
    myParagraphVNode<span class="token punctuation">,</span> myParagraphVNode
  <span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>如果你真的需要重复很多次的元素/组件，你可以使用工厂函数来实现。例如，下面这渲染函数用完全合法的方式渲染了 20 个相同的段落：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span>
    Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> length<span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token string">'hi'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h2 id="创建组件-vnode"><a href="#创建组件-vnode" class="header-anchor">#</a> 创建组件 VNode</h2> <p>要为某个组件创建一个 VNode，传递给 <code>h</code> 的第一个参数应该是组件本身。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>ButtonCounter<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>如果我们需要通过名称来解析一个组件，那么我们可以调用 <code>resolveComponent</code>：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> h<span class="token punctuation">,</span> resolveComponent <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token comment">// ...</span>

<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> ButtonCounter <span class="token operator">=</span> <span class="token function">resolveComponent</span><span class="token punctuation">(</span><span class="token string">'ButtonCounter'</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>ButtonCounter<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p><code>resolveComponent</code> 是模板内部用来解析组件名称的同一个函数。</p> <p><code>render</code> 函数通常只需要对<a href="/vue3/guide/component-registration.html#global-registration">全局注册</a>的组件使用 <code>resolveComponent</code>。而对于<a href="/vue3/guide/component-registration.html#local-registration">局部注册</a>的却可以跳过，请看下面的例子：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// 此写法可以简化</span>
components<span class="token operator">:</span> <span class="token punctuation">{</span>
  ButtonCounter
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token function">resolveComponent</span><span class="token punctuation">(</span><span class="token string">'ButtonCounter'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>我们可以直接使用它，而不是通过名称注册一个组件，然后再查找：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>ButtonCounter<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h2 id="使用-javascript-代替模板功能"><a href="#使用-javascript-代替模板功能" class="header-anchor">#</a> 使用 JavaScript 代替模板功能</h2> <h3 id="v-if-和-v-for"><a href="#v-if-和-v-for" class="header-anchor">#</a> <code>v-if</code> 和 <code>v-for</code></h3> <p>只要在原生的 JavaScript 中可以轻松完成的操作，Vue 的渲染函数就不会提供专有的替代方法。比如，在模板中使用的 <code>v-if</code> 和 <code>v-for</code>：</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>items.length<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>item in items<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{ item.name }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">v-else</span><span class="token punctuation">&gt;</span></span>No items found.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>这些都可以在渲染函数中用 JavaScript 的 <code>if</code>/<code>else</code> 和 <code>map()</code> 来重写：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>props<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'items'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'ul'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'li'</span><span class="token punctuation">,</span> item<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token string">'No items found.'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h3 id="v-model"><a href="#v-model" class="header-anchor">#</a> <code>v-model</code></h3> <p><code>v-model</code> 指令扩展为 <code>modelValue</code> 和 <code>onUpdate:modelValue</code> 在模板编译过程中，我们必须自己提供这些 prop：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>props<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'modelValue'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
emits<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'update:modelValue'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>SomeComponent<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    modelValue<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>modelValue<span class="token punctuation">,</span>
    <span class="token string">'onUpdate:modelValue'</span><span class="token operator">:</span> <span class="token parameter">value</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">$emit</span><span class="token punctuation">(</span><span class="token string">'update:modelValue'</span><span class="token punctuation">,</span> value<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h3 id="v-on"><a href="#v-on" class="header-anchor">#</a> <code>v-on</code></h3> <p>我们必须为事件处理程序提供一个正确的 prop 名称，例如，要处理 <code>click</code> 事件，prop 名称应该是 <code>onClick</code>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token function-variable function">onClick</span><span class="token operator">:</span> <span class="token parameter">$event</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'clicked'</span><span class="token punctuation">,</span> $event<span class="token punctuation">.</span>target<span class="token punctuation">)</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h4 id="事件修饰符"><a href="#事件修饰符" class="header-anchor">#</a> 事件修饰符</h4> <p>对于 <code>.passive</code> 、<code>.capture</code> 和 <code>.once</code> 事件修饰符，可以使用驼峰写法将他们拼接在事件名后面：</p> <p>实例:</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    onClickCapture<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>doThisInCapturingMode<span class="token punctuation">,</span>
    onKeyupOnce<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>doThisOnce<span class="token punctuation">,</span>
    onMouseoverOnceCapture<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>doThisOnceInCapturingMode
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>对于所有其它的修饰符，私有前缀都不是必须的，因为你可以在事件处理函数中使用事件方法：</p> <table><thead><tr><th>修饰符</th> <th>处理函数中的等价操作</th></tr></thead> <tbody><tr><td><code>.stop</code></td> <td><code>event.stopPropagation()</code></td></tr> <tr><td><code>.prevent</code></td> <td><code>event.preventDefault()</code></td></tr> <tr><td><code>.self</code></td> <td><code>if (event.target !== event.currentTarget) return</code></td></tr> <tr><td>按键：<br><code>.enter</code>, <code>.13</code></td> <td><code>if (event.keyCode !== 13) return</code> (对于别的按键修饰符来说，可将 13 改为<a href="http://keycode.info/" target="_blank" rel="noopener noreferrer">另一个按键码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></td></tr> <tr><td>修饰键：<br><code>.ctrl</code>, <code>.alt</code>, <code>.shift</code>, <code>.meta</code></td> <td><code>if (!event.ctrlKey) return</code> (将 <code>ctrlKey</code> 分别修改为 <code>altKey</code>, <code>shiftKey</code>, 或 <code>metaKey</code>)</td></tr></tbody></table> <p>这里是一个使用所有修饰符的例子：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token function-variable function">onKeyUp</span><span class="token operator">:</span> <span class="token parameter">event</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 如果触发事件的元素不是事件绑定的元素</span>
      <span class="token comment">// 则返回</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>target <span class="token operator">!==</span> event<span class="token punctuation">.</span>currentTarget<span class="token punctuation">)</span> <span class="token keyword">return</span>
      <span class="token comment">// 如果向上键不是回车键，则终止</span>
      <span class="token comment">// 没有同时按下按键 (13) 和 shift 键</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>event<span class="token punctuation">.</span>shiftKey <span class="token operator">||</span> event<span class="token punctuation">.</span>keyCode <span class="token operator">!==</span> <span class="token number">13</span><span class="token punctuation">)</span> <span class="token keyword">return</span>
      <span class="token comment">// 停止事件传播</span>
      event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token comment">// 阻止该元素默认的 keyup 事件</span>
      event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token comment">// ...</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><h3 id="插槽"><a href="#插槽" class="header-anchor">#</a> 插槽</h3> <p>你可以通过 <a href="/vue3/api/instance-properties.html#slots"><code>this.$slots</code></a> 访问静态插槽的内容，每个插槽都是一个 VNode 数组：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// `&lt;div&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/div&gt;`</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><div class="language-js line-numbers-mode"><pre class="language-js"><code>props<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'message'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// `&lt;div&gt;&lt;slot :text=&quot;message&quot;&gt;&lt;/slot&gt;&lt;/div&gt;`</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    text<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>message
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>要使用渲染函数将插槽传递给子组件，请执行以下操作：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> h<span class="token punctuation">,</span> resolveComponent <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// `&lt;div&gt;&lt;child v-slot=&quot;props&quot;&gt;&lt;span&gt;{{ props.text }}&lt;/span&gt;&lt;/child&gt;&lt;/div&gt;`</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>
    <span class="token function">h</span><span class="token punctuation">(</span>
      <span class="token function">resolveComponent</span><span class="token punctuation">(</span><span class="token string">'child'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token comment">// 将 `slots` 以 { name: props =&gt; VNode | Array&lt;VNode&gt; } 的形式传递给子对象。</span>
      <span class="token punctuation">{</span>
        <span class="token function-variable function">default</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> Vue<span class="token punctuation">.</span><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'span'</span><span class="token punctuation">,</span> props<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">)</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>插槽以函数的形式传递，允许子组件控制每个插槽内容的创建。任何响应式数据都应该在插槽函数内访问，以确保它被注册为子组件的依赖关系，而不是父组件。相反，对 <code>resolveComponent</code> 的调用应该在插槽函数之外进行，否则它们会相对于错误的组件进行解析。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// `&lt;MyButton&gt;&lt;MyIcon :name=&quot;icon&quot; /&gt;{{ text }}&lt;/MyButton&gt;`</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 应该是在插槽函数外面调用 resolveComponent。</span>
  <span class="token keyword">const</span> Button <span class="token operator">=</span> <span class="token function">resolveComponent</span><span class="token punctuation">(</span><span class="token string">'MyButton'</span><span class="token punctuation">)</span>
  <span class="token keyword">const</span> Icon <span class="token operator">=</span> <span class="token function">resolveComponent</span><span class="token punctuation">(</span><span class="token string">'MyIcon'</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>
    Button<span class="token punctuation">,</span>
    <span class="token keyword">null</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token comment">// 使用箭头函数保存 `this` 的值</span>
      <span class="token function-variable function">default</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token comment">// 响应式 property 应该在插槽函数内部读取，</span>
        <span class="token comment">// 这样它们就会成为 children 渲染的依赖。</span>
        <span class="token keyword">return</span> <span class="token punctuation">[</span>
          <span class="token function">h</span><span class="token punctuation">(</span>Icon<span class="token punctuation">,</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>icon <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>text
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><p>如果一个组件从它的父组件中接收到插槽，它们可以直接传递给子组件。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>Panel<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>也可以根据情况单独传递或包裹住。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>
    Panel<span class="token punctuation">,</span>
    <span class="token keyword">null</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token comment">// 如果我们想传递一个槽函数，我们可以通过</span>
      header<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span>header<span class="token punctuation">,</span>

      <span class="token comment">// 如果我们需要以某种方式对插槽进行操作，</span>
      <span class="token comment">// 那么我们需要用一个新的函数来包裹它</span>
      <span class="token function-variable function">default</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> children <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span>default <span class="token operator">?</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$slots<span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>

        <span class="token keyword">return</span> children<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">,</span> <span class="token string">'Extra child'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><h3 id="component-和-is"><a href="#component-和-is" class="header-anchor">#</a> <code>&lt;component&gt;</code> 和 <code>is</code></h3> <p>在底层实现里，模板使用 <code>resolveDynamicComponent</code> 来实现 <code>is</code> attribute。如果我们在 <code>render</code> 函数中需要 <code>is</code> 提供的所有灵活性，我们可以使用同样的函数：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> h<span class="token punctuation">,</span> resolveDynamicComponent <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token comment">// ...</span>

<span class="token comment">// `&lt;component :is=&quot;name&quot;&gt;&lt;/component&gt;`</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> Component <span class="token operator">=</span> <span class="token function">resolveDynamicComponent</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>Component<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>就像 <code>is</code>, <code>resolveDynamicComponent</code> 支持传递一个组件名称、一个 HTML 元素名称或一个组件选项对象。</p> <p>通常这种程度的灵活性是不需要的。通常 <code>resolveDynamicComponent</code> 可以被换做一个更直接的替代方案。</p> <p>例如，如果我们只需要支持组件名称，那么可以使用 <code>resolveComponent</code> 来代替。</p> <p>如果 VNode 始终是一个 HTML 元素，那么我们可以直接把它的名字传递给 <code>h</code>：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// `&lt;component :is=&quot;bold ? 'strong' : 'em'&quot;&gt;&lt;/component&gt;`</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>bold <span class="token operator">?</span> <span class="token string">'strong'</span> <span class="token operator">:</span> <span class="token string">'em'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>同样，如果传递给 <code>is</code> 的值是一个组件选项对象，那么不需要解析什么，可以直接作为 <code>h</code> 的第一个参数传递。</p> <p>与 <code>&lt;template&gt;</code> 标签一样，<code>&lt;component&gt;</code> 标签仅在模板中作为语法占位符需要，当迁移到 <code>render</code> 函数时，应被丢弃。</p> <h3 id="自定义指令"><a href="#自定义指令" class="header-anchor">#</a> 自定义指令</h3> <p>可以使用 <a href="/vue3/api/global-api.html#withdirectives"><code>withDirectives</code></a> 将自定义指令应用于 VNode：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> h<span class="token punctuation">,</span> resolveDirective<span class="token punctuation">,</span> withDirectives <span class="token punctuation">}</span> <span class="token operator">=</span> Vue

<span class="token comment">// ...</span>

<span class="token comment">// &lt;div v-pin:top.animate=&quot;200&quot;&gt;&lt;/div&gt;</span>
<span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pin <span class="token operator">=</span> <span class="token function">resolveDirective</span><span class="token punctuation">(</span><span class="token string">'pin'</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> <span class="token function">withDirectives</span><span class="token punctuation">(</span><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>
    <span class="token punctuation">[</span>pin<span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token string">'top'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> animate<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">]</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p><a href="/vue3/api/global-api.html#resolvedirective"><code>resolveDirective</code></a> 是模板内部用来解析指令名称的同一个函数。只有当你还没有直接访问指令的定义对象时，才需要这样做。</p> <h3 id="内置组件"><a href="#内置组件" class="header-anchor">#</a> 内置组件</h3> <p>诸如 <code>&lt;keep-alive&gt;</code>、<code>&lt;transition&gt;</code>、<code>&lt;transition-group&gt;</code> 和 <code>&lt;teleport&gt;</code> 等<a href="/vue3/api/built-in-components.html">内置组件</a>默认并没有被全局注册。这使得打包工具可以 tree-shake，因此这些组件只会在被用到的时候被引入构建。不过这也意味着我们无法通过 <code>resolveComponent</code> 或 <code>resolveDynamicComponent</code> 访问它们。</p> <p>在模板中这些组件会被特殊处理，即在它们被用到的时候自动导入。当我们编写自己的 <code>render</code> 函数时，需要自行导入它们：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token punctuation">{</span> h<span class="token punctuation">,</span> KeepAlive<span class="token punctuation">,</span> Teleport<span class="token punctuation">,</span> Transition<span class="token punctuation">,</span> TransitionGroup <span class="token punctuation">}</span> <span class="token operator">=</span> Vue
<span class="token comment">// ...</span>
<span class="token function">render</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">h</span><span class="token punctuation">(</span>Transition<span class="token punctuation">,</span> <span class="token punctuation">{</span> mode<span class="token operator">:</span> <span class="token string">'out-in'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">/* ... */</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h2 id="渲染函数的返回值"><a href="#渲染函数的返回值" class="header-anchor">#</a> 渲染函数的返回值</h2> <p>在我们目前看过的所有示例中，<code>render</code> 函数返回的是单个根 VNode。但其实也有别的选项。</p> <p>返回一个字符串时会创建一个文本 VNode，而不被包裹任何元素：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token string">'Hello world!'</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>我们也可以返回一个子元素数组，而不把它们包裹在一个根结点里。这会创建一个片段 (fragment)：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// 相当于模板 `Hello&lt;br&gt;world!`</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">[</span>
    <span class="token string">'Hello'</span><span class="token punctuation">,</span>
    <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'br'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token string">'world!'</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>可能是因为数据依然在加载中的关系，组件不需要渲染，这时它可以返回 <code>null</code>。这样我们在 DOM 中会渲染一个注释节点。</p> <h2 id="jsx"><a href="#jsx" class="header-anchor">#</a> JSX</h2> <p>如果你写了很多渲染函数，可能会觉得下面这样的代码写起来很痛苦：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token function">h</span><span class="token punctuation">(</span>
  <span class="token string">'anchored-heading'</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    level<span class="token operator">:</span> <span class="token number">1</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    <span class="token function-variable function">default</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'span'</span><span class="token punctuation">,</span> <span class="token string">'Hello'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">' world!'</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>特别是对应的模板如此简单的情况下：</p> <div class="language-vue-html line-numbers-mode"><pre class="language-vue-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>anchored-heading</span> <span class="token directive"><span class="token punctuation directive-shorthand">:</span><span class="token directive-modifier"><span class="token punctuation">l</span><span class="token punctuation">e</span><span class="token punctuation">v</span><span class="token punctuation">e</span><span class="token punctuation">l</span></span><span class="token directive-expression"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token inline-js language-js"><span class="token number">1</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span> world! <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>anchored-heading</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这就是为什么会有一个 <a href="https://github.com/vuejs/jsx-next" target="_blank" rel="noopener noreferrer">Babel 插件<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，用于在 Vue 中使用 JSX 语法，它可以让我们回到更接近于模板的语法上。</p> <div class="language-jsx line-numbers-mode"><pre class="language-jsx"><code><span class="token keyword">import</span> AnchoredHeading <span class="token keyword">from</span> <span class="token string">'./AnchoredHeading.vue'</span>

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">createApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">AnchoredHeading</span></span> <span class="token attr-name">level</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">}</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">&gt;</span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span><span class="token plain-text"> world!
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">AnchoredHeading</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

app<span class="token punctuation">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string">'#demo'</span><span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>有关 JSX 如何映射到 JavaScript 的更多信息，请参阅<a href="https://github.com/vuejs/jsx-next#installation" target="_blank" rel="noopener noreferrer">使用文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 。</p> <h2 id="函数式组件"><a href="#函数式组件" class="header-anchor">#</a> 函数式组件</h2> <p>函数式组件是自身没有任何状态的组件的另一种形式。它们在渲染过程中不会创建组件实例，并跳过常规的组件生命周期。</p> <p>我们使用的是一个简单函数，而不是一个选项对象，来创建函数式组件。该函数实际上就是该组件的 <code>render</code> 函数。而因为函数式组件里没有 <code>this</code> 引用，Vue 会把 <code>props</code> 当作第一个参数传入：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">FunctionalComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">props<span class="token punctuation">,</span> context</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>第二个参数 <code>context</code> 包含三个 property：<code>attrs</code>、<code>emit</code> 和 <code>slots</code>。它们分别相当于实例的 <a href="/vue3/api/instance-properties.html#attrs"><code>$attrs</code></a>、<a href="/vue3/api/instance-methods.html#emit"><code>$emit</code></a> 和 <a href="/vue3/api/instance-properties.html#slots"><code>$slots</code></a> 这几个 property。</p> <p>大多数常规组件的配置选项在函数式组件中都不可用。然而我们还是可以把 <a href="/vue3/api/options-data.html#props"><code>props</code></a> 和 <a href="/vue3/api/options-data.html#emits"><code>emits</code></a> 作为 property 加入，以达到定义它们的目的：</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>FunctionalComponent<span class="token punctuation">.</span>props <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'value'</span><span class="token punctuation">]</span>
FunctionalComponent<span class="token punctuation">.</span>emits <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'click'</span><span class="token punctuation">]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>如果这个 <code>props</code> 选项没有被定义，那么被传入函数的 <code>props</code> 对象就会像 <code>attrs</code> 一样会包含所有 attribute。除非指定了 <code>props</code> 选项，否则每个 prop 的名字将不会基于驼峰命名法被一般化处理。</p> <p>函数式组件可以像普通组件一样被注册和消费。如果你将一个函数作为第一个参数传入 <code>h</code>，它将会被当作一个函数式组件来对待。</p> <h2 id="模板编译"><a href="#模板编译" class="header-anchor">#</a> 模板编译</h2> <p>你可能会有兴趣知道，Vue 的模板实际上被编译成了渲染函数。这是一个实现细节，通常不需要关心。但如果你想看看模板的功能具体是怎样被编译的，可能会发现会非常有意思。下面是一个使用 <code>Vue.compile</code> 来实时编译模板字符串的简单示例：</p> <iframe src="https://vue-next-template-explorer.netlify.app/" width="100%" height="420"></iframe></div> <footer class="page-edit" data-v-007274aa><div class="container" data-v-007274aa><p data-v-007274aa><span class="edit-link" data-v-007274aa>
         发现了错误或者想要为文档做贡献？
          <a href="https://github.com/vuejs/docs-next-zh-cn/edit/master/src/guide/render-function.md" target="_blank" rel="noopener noreferrer" data-v-007274aa>
            在 GitHub 上编辑此页
            <span data-v-007274aa><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></span> <!----></p></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/vue3/guide/teleport.html" class="prev">Teleport</a></span> <span class="next"><a href="/vue3/guide/plugins.html">插件</a>
      →
    </span></p></div> <div class="bsa-cpc-wrapper"><div class="bsa-cpc"></div></div> </main></div><div class="global-ui"><!----></div></div>
    <script src="/vue3/assets/js/app.9f011487.js" defer></script><script src="/vue3/assets/js/11.bea13863.js" defer></script><script src="/vue3/assets/js/163.c2f8c96a.js" defer></script><script src="/vue3/assets/js/23.f23a1976.js" defer></script>
  </body>
</html>
